const crypto = require('crypto')
let vertoken = require("../utils/token")
const { Query } = require('../utils/query')
const { RespError, RespSuccess, RespData } = require('../utils/resp')
const { AuthErrStatus, CommonErrStatus } = require('../utils/error')
const { base64ToImage } = require('../utils/file')
const moment = require("moment")
const fs = require('fs')
const path = require('path')

class AdminServices {
  /**
   * 登录
   * @param {username} 用户名
   * @param {password} 密码
   * 登录的基本逻辑：
   * 1. 获取到前端传来的 username 和 password
   * 2. 查询数据库，判断用户名和密码是否正确
   * 3.正确后生成 jwt, 返回 token 给前端去保存
   */
  async login (ctx, next) {
    const { userName, password } = ctx.request.body
    if (!(userName && password)) {
      return RespError(ctx, CommonErrStatus.PARAM_ERR)
    }
    try {
      const sql = `SELECT * FROM sys_user WHERE user_name = ?`
      const results = await Query(sql, [userName])
      if (results.length !== 0) {
        // 1. 获取到用户信息
        const payload = {
          id: results[0].id,
          userName: results[0].userName,
          nickName: results[0].nickName,
          password: results[0].password,
          salt: results[0].salt
        }
        // 2. 加盐
        const M = payload.salt.slice(0, 3) + password + payload.salt.slice(3)
        // 3. 将 M 进行 MD5 哈希，得到哈希值
        const hash = crypto.createHash('md5').update(M).digest('hex')
        if (hash !== payload.password) {
          return RespError(ctx, AuthErrStatus.USER_OR_PASS_ERR)
        }
        // 4. 生成 jwt，之后 payload 会携带在请求头的 req.user 中（前提是通过了中间件）
        const payloadForm = {
          userId: results[0].userId,
          userName: results[0].userName,
          nickName: results[0].nickName,
          salt: results[0].salt
        }
        const token = await vertoken.setToken(payloadForm)
        const data = {
          token: token,
          info: {
            ...results[0]
          }
        }
        return RespData(ctx, data)
      } else {
        return RespError(ctx, AuthErrStatus.USER_DOES_NOT_EXIST)
      }

    } catch (error) {
      return RespError(ctx, CommonErrStatus.SERVER_ERR)
    }
  }
  /**
   * 退出
   */
  async logout (ctx, next) {
    try {
      // 将登录信息清空
      ctx.session = null
      return RespData(ctx, { massage: '退出' })
    } catch {
      return RespError(res, CommonErrStatus.SERVER_ERR)
    }
  }
  /**
     * 注册
     * @param {username} 用户名（不允许重复）
     * @param {password} 密码
     * 登录的基本逻辑：
     * 1. 获取到前端传来的 username 和 password
     * 2. 查询数据库，是否存在用户
     * 3.存在用户返回信息：该用户已存在
     * 4.用户不存在，则新建用户信息
     */
  async register (ctx, next) {
    const { userName, password } = ctx.request.body
    if (!(userName && password)) {
      return RespError(ctx, CommonErrStatus.PARAM_ERR)
    }
    try {
      // 判断用户名是否已经注册
      const sql_check = `SELECT user_name FROM sys_user WHERE user_name = ?`
      const results_check = await Query(sql_check, [userName])
      if (results_check.length !== 0) {
        // 用户名已经注册
        return RespError(ctx, AuthErrStatus.USER_EXIT_ERR)
      }
      // 加盐（3 个字节的字节码转化成 16 进制字符串，生成一个 6 位的 salt）
      const salt = crypto.randomBytes(3).toString('hex')
      const M = salt.slice(0, 3) + password + salt.slice(3)
      // 将 M 进行 MD5 哈希，得到哈希值
      const hash = crypto.createHash('md5').update(M).digest('hex')
      const user = {
        user_name: userName,
        password: hash,
        nickName: userName,
        createBy: userName,
        createTime: moment().format("YYYY-MM-DD HH:mm:ss"),
        updateTime: moment().format("YYYY-MM-DD HH:mm:ss"),
        updateBy: userName,
        salt: salt
      }
      // 插入 user 表中
      const sql_set_user = `INSERT INTO sys_user SET ?`
      const results_set_user = await Query(sql_set_user, user)
      // 注册成功后将相关信息返回给前端
      if (results_set_user.affectedRows === 1) {
        const sql_get_user = `SELECT * FROM sys_user WHERE user_name = ?`
        const results_get_user = await Query(sql_get_user, [userName])
        const info = results_get_user[0]
        // 生成 jwt
        const payload = {
          id: info.userId,
          userName: info.userName,
          nickName: info.nickName,
          salt: info.salt
        }
        const token = await vertoken.setToken(payload)
        // 返回 token 和用户信息
        const data = {
          token: token,
          info: info,
        }
        return RespData(ctx, data)
      }
    } catch (error) {
      // 创建失败
      return RespError(ctx, CommonErrStatus.CREATE_ERR)
    }
  }
  /**
   * 修改密码
   * @param {username} 用户名（不允许重复）
   * @param {password} 密码
   * 忘记密码/修改密码的基本逻辑：
   * 1. 判断用户手机号和用户名是否存在
   * 2. 如果数据符合则修改 user 表的数据（密码重新加盐哈希）
   * 3. 前端重新登录
   */
  async forgetPassword (ctx, next) {
    const { userName, password } = ctx.request.body
    console.log('forgetPassword', userName, password)
    ctx.body = ctx.request.body
  }
  /**
   * 修改用户信息
   * @param {username} 用户名（不允许重复）
   * @param {avatar} 头像
   * @param {phone} 手机号
   * @param {address} 地址
   * @param {signature} 个性签名
   * 修改用户信息的基本逻辑：
   * 1. 获取到前端传来的更新信息，判断新手机号是否已被注册，若未被注册则直接更新 user 表中的数据
   * 2. 生成 jwt, 返回新的用户信息和 token 给前端
   * 3. 前端重新刷新相关信息
   */
  async updateInfo (ctx, next) {
    const { userName, avatar, name, phone, signature } = ctx.request.body
    console.log('forgetPassword', userName, avatar, name, phone, signature)
    ctx.body = ctx.request.body
  }

  // 修改头像
  async profileAvatar (ctx, next) {
    let { body } = ctx.request // 
    let { userId } = ctx.body
    // const { authorization } = ctx.request.headers
    // let info = await vertoken.getToken(authorization) // 根据当前账号信息，更改数据库中头像地址
    try {
      // 查询数据库中的用户信息
      let sql_ = `SELECT sys_user.* FROM sys_user WHERE sys_user.user_id = ?`
      let userInfo = await Query(sql_, userId) // 请求当前账号的信息，
      let avatar = userInfo[0].avatar
      // 判断头像是否存在
      let da = __dirname.match(/(\S*)services/)[1] // 获取到当前文件夹前的url
      let oldFilePath = path.join(da, avatar) // 当前头像的完整路径
      // 判断头像路由是否存在,存在就删除头像
      if (fs.existsSync(oldFilePath)) {
        let data = await fs.unlink(oldFilePath, (err) => {
          if (err) {
          }
          return true
        })
      }
      // 上传新头像,并且返回头像的地址路径
      const filePath = base64ToImage(body.name, body.base64)
      console.log('filePath', filePath)
      let sql = `UPDATE jwzs_database.sys_user SET avatar = ? WHERE user_id = ${userId};` // 更新当前账号数据库信息
      let result = await Query(sql, [filePath])
      console.log('result', result)
      // 返回头像地址
      const results = {
        filePath,
        ...result
      }
      return RespData(ctx, results)
    } catch (err) {
      return RespError(ctx, CommonErrStatus.SERVER_ERR)
    }
  }
}

module.exports = new AdminServices()